package com.mofang.ticketing.user.serve.account.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.mofang.ticketing.common.core.constant.AccountConstant;
import com.mofang.ticketing.common.core.dto.PrimaryIdDTO;
import com.mofang.ticketing.common.core.enums.account.AccountTypeEnum;
import com.mofang.ticketing.common.core.enums.account.BelongEnum;
import com.mofang.ticketing.common.core.enums.account.IsAdminEnum;
import com.mofang.ticketing.common.core.enums.account.RoleTypeEnum;
import com.mofang.ticketing.common.core.exception.BizException;
import com.mofang.ticketing.common.redis.config.BusinessSnGenerator;
import com.mofang.ticketing.common.redis.constant.RedisConstant;
import com.mofang.ticketing.common.redis.service.RedisService;
import com.mofang.ticketing.common.security.util.SecurityUtil;
import com.mofang.ticketing.user.mapping.entity.*;
import com.mofang.ticketing.user.mapping.mapper.*;
import com.mofang.ticketing.user.serve.account.dto.request.*;
import com.mofang.ticketing.user.serve.account.dto.response.PlatformAccountListPageRespDTO;
import com.mofang.ticketing.user.serve.account.mapper.AccountMapper;
import com.mofang.ticketing.user.serve.account.service.AuthService;
import com.mofang.ticketing.user.serve.account.service.PlatformAccountService;
import com.mofang.ticketing.user.serve.project.service.ProjectService;
import com.mofang.ticketing.user.serve.role.mapper.RoleMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author LGC
 * @date 2023/3/14 13:41
 */
@Slf4j
@Service
public class PlatformAccountServiceImpl implements PlatformAccountService {
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private SysUserDOMapper sysUserDOMapper;
    @Resource
    private SysRoleDOMapper sysRoleDOMapper;
    @Resource
    private SysUserRoleDOMapper sysUserRoleDOMapper;
    @Resource
    private MerchantInfoDOMapper merchantInfoDOMapper;
    @Resource
    private ProjectInfoDOMapper projectInfoDOMapper;
    @Resource
    private ProjectUserDOMapper projectUserDOMapper;
    @Resource
    private AccountMapper accountMapper;
    @Resource
    private RedisService redisService;
    @Resource
    private BusinessSnGenerator businessSnGenerator;
    @Resource
    private ProjectService projectService;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private AuthService authService;

    @Override
    public IPage<PlatformAccountListPageRespDTO> platformAccountListPage(PlatformAccountListPageReqDTO dto) {
        IPage<PlatformAccountListPageRespDTO> pageResult = accountMapper.selectPlatformAccountListPage(dto.getPage().getPage(), dto);
        List<PlatformAccountListPageRespDTO> records = pageResult.getRecords();
        for (PlatformAccountListPageRespDTO record : records) {
            if (record.getAccountType().equals(AccountTypeEnum.MERCHANT_ADMIN.getKey())) {
                record.setMerchantName(accountMapper.selectUserBelongMerchant(record.getId(), record.getBelong())
                        .stream().map(MerchantInfoDO::getMerchantName).collect(Collectors.joining(",")));
            }
            if (record.getAccountType().equals(AccountTypeEnum.MERCHANT_MEMBER.getKey())) {
                MerchantInfoDO merchant = accountMapper.selectUserBelongMerchant(record.getId(), record.getBelong()).get(0);
                record.setMerchantId(merchant.getId());
                record.setMerchantName(merchant.getMerchantName());
            }
            if (record.getAccountType().equals(AccountTypeEnum.PROJECT_MEMBER.getKey())) {
                ProjectInfoDO project = accountMapper.selectUserBelongProject(record.getId(), record.getBelong());
                record.setProjectId(project.getId());
                record.setProjectName(project.getProjectName());
            }
        }
        return pageResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void platformAccountAdd(PlatformAccountAddReqDTO dto) {
        Long userId = SecurityUtil.getUserId();
        Integer accountType = dto.getAccountType();
        if (accountType.equals(AccountTypeEnum.PLATFORM_ADMIN.getKey())) {
            if (StrUtil.isBlank(dto.getAccount()) || StrUtil.isBlank(dto.getUsername())) {
                throw new BizException("添加平台管理员账号，手机号或用户名不能为空");
            }
            Long count = new LambdaQueryChainWrapper<>(sysUserDOMapper)
                    .eq(SysUserDO::getAccount, dto.getAccount()).count();
            if (count > 0) {
                throw new BizException("该账号已被注册使用");
            }
            SysUserDO insertAccount = authService.insertAccount(BelongEnum.PLATFORM, AccountTypeEnum.PLATFORM_ADMIN, dto.getUsername(), dto.getAccount(), userId);
            sysUserRoleDOMapper.insert(new SysUserRoleDO(BelongEnum.PLATFORM.getKey(), 0L,
                    insertAccount.getId(), roleMapper.selectRoleByRoleCode(RoleTypeEnum.PLATFORM_ADMIN.getRoleCode()).getId()));
        }
        if (accountType.equals(AccountTypeEnum.MERCHANT_MEMBER.getKey())) {
            if (StrUtil.isBlank(dto.getUsername()) || dto.getMerchantId() == null || dto.getRoleId() == null) {
                throw new BizException("添加商户成员账号，用户名、商户、角色不能为空");
            }
            MerchantInfoDO merchantInfoDO = merchantInfoDOMapper.selectById(dto.getMerchantId());
            if (merchantInfoDO == null) {
                throw new BizException("添加商户成员账号，商户不存在");
            }
            SysRoleDO sysRoleDO = sysRoleDOMapper.selectById(dto.getRoleId());
            if (sysRoleDO == null) {
                throw new BizException("添加商户成员账号，角色不存在");
            }
            String account = businessSnGenerator.generateMerchantMemberAccount(AccountConstant.MERCHANT_MEMBER_PREFIX);
            SysUserDO insertAccount = authService.insertAccount(BelongEnum.MERCHANT, AccountTypeEnum.MERCHANT_MEMBER, dto.getUsername(), account, userId);
            sysUserRoleDOMapper.insert(new SysUserRoleDO(BelongEnum.MERCHANT.getKey(), dto.getMerchantId(),
                    insertAccount.getId(), dto.getRoleId()));
        }
        if (accountType.equals(AccountTypeEnum.PROJECT_MEMBER.getKey())) {
            if (StrUtil.isBlank(dto.getUsername()) || dto.getProjectId() == null) {
                throw new BizException("添加项目成员账号，用户名、项目不能为空");
            }
            ProjectInfoDO projectInfoDO = projectInfoDOMapper.selectById(dto.getProjectId());
            if (projectInfoDO == null) {
                throw new BizException("添加项目成员账号，项目不存在");
            }
            String account = businessSnGenerator.generateMerchantMemberAccount(AccountConstant.PROJECT_MEMBER_PREFIX);
            SysUserDO insertAccount = authService.insertAccount(BelongEnum.PROJECT_MEMBER, AccountTypeEnum.PROJECT_MEMBER, dto.getUsername(), account, userId);
            // 插入项目用户角色关系
            Set<Long> merchantIds = projectService.getMerchantIdSetByProject(projectInfoDO);
            projectService.insetProjectUserRole(insertAccount.getId(), merchantIds, projectInfoDO.getId());
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void platformAccountUpdate(PlatformAccountUpdateReqDTO dto) {
        SysUserDO sysUserDO = sysUserDOMapper.selectById(dto.getId());
        if (sysUserDO == null) {
            throw new BizException("账号不存在");
        }
        Integer accountType = sysUserDO.getAccountType();
        if (accountType.equals(AccountTypeEnum.PLATFORM_ADMIN.getKey())) {
            if (sysUserDO.getIsAdmin().equals(IsAdminEnum.ADMIN.getKey())) {
                throw new BizException("初始化平台管理员账号不能修改");
            }
            if (StrUtil.isBlank(dto.getUsername())) {
                throw new BizException("修改平台管理员账号，用户名不能为空");
            }
        }
        if (accountType.equals(AccountTypeEnum.MERCHANT_ADMIN.getKey())) {
            throw new BizException("商户管理管理员账号不能修改");
        }
        if (accountType.equals(AccountTypeEnum.MERCHANT_MEMBER.getKey())) {
            if (StrUtil.isBlank(dto.getUsername()) || dto.getMerchantId() == null || dto.getRoleId() == null) {
                throw new BizException("修改商户成员账号，用户名、商户、角色不能为空");
            }
            MerchantInfoDO merchantInfoDO = merchantInfoDOMapper.selectById(dto.getMerchantId());
            if (merchantInfoDO == null) {
                throw new BizException("修改商户成员账号，商户不存在");
            }
            SysRoleDO sysRoleDO = sysRoleDOMapper.selectById(dto.getRoleId());
            if (sysRoleDO == null) {
                throw new BizException("修改商户成员账号，角色不存在");
            }
            // 商户和角色发生改变 删除旧绑定关系 新增绑定关系 退出登录
            SysUserRoleDO oldUserRole = new LambdaQueryChainWrapper<>(sysUserRoleDOMapper)
                    .eq(SysUserRoleDO::getUserId, sysUserDO.getId())
                    .eq(SysUserRoleDO::getBelong, BelongEnum.MERCHANT.getKey()).one();
            if (!dto.getMerchantId().equals(oldUserRole.getMerchantId()) || !dto.getRoleId().equals(oldUserRole.getRoleId())) {
                sysUserRoleDOMapper.deleteById(oldUserRole.getId());
                SysUserRoleDO insertUserRoleDO = new SysUserRoleDO(BelongEnum.MERCHANT.getKey(), dto.getMerchantId(),
                        sysUserDO.getId(), dto.getRoleId());
                sysUserRoleDOMapper.insert(insertUserRoleDO);
            }
        }
        if (accountType.equals(AccountTypeEnum.PROJECT_MEMBER.getKey())) {
            if (StrUtil.isBlank(dto.getUsername()) || dto.getProjectId() == null) {
                throw new BizException("修改项目成员账号，用户名、项目不能为空");
            }
            ProjectInfoDO projectInfoDO = projectInfoDOMapper.selectById(dto.getProjectId());
            if (projectInfoDO == null) {
                throw new BizException("修改项目成员账号，项目不存在");
            }
            // 项目发生改变 一个项目成员只能在一个项目中
            List<ProjectUserDO> oldProjectUserList = new LambdaQueryChainWrapper<>(projectUserDOMapper)
                    .eq(ProjectUserDO::getUserId, sysUserDO.getId()).list();
            if (CollUtil.isNotEmpty(oldProjectUserList)) {
                ProjectUserDO projectUserDO = oldProjectUserList.get(0);
                Long projectId = projectUserDO.getProjectId();
                if (!dto.getProjectId().equals(projectId)) {
                    // 移除项目用户角色关系
                    Set<Long> userIdSet = new HashSet<>(1);
                    userIdSet.add(sysUserDO.getId());
                    projectService.removeProjectUserRole(userIdSet);

                    // 插入项目用户角色关系
                    Set<Long> merchantIds = projectService.getMerchantIdSetByProject(projectInfoDO);
                    projectService.insetProjectUserRole(sysUserDO.getId(), merchantIds, projectInfoDO.getId());
                }
            }
        }
        // 更新用户名
        boolean updateUsername = authService.updateUsername(dto.getUsername(), sysUserDO);
        if (!updateUsername) {
            throw new BizException("更新用户名失败");
        }
        redisService.del(String.format(RedisConstant.LOGIN_INFO_KEY, sysUserDO.getAccount()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void platformAccountEnable(PrimaryIdDTO dto) {
        SysUserDO sysUserDO = sysUserDOMapper.selectById(dto.getId());
        if (sysUserDO == null) {
            throw new BizException("账号不存在");
        }
        Integer accountType = sysUserDO.getAccountType();
        if (accountType.equals(AccountTypeEnum.PLATFORM_ADMIN.getKey())) {
            if (sysUserDO.getIsAdmin().equals(IsAdminEnum.ADMIN.getKey())) {
                throw new BizException("初始化平台管理员账号不能禁用启用");
            }
            log.info("平台管理员账号禁用");
        }
        if (accountType.equals(AccountTypeEnum.MERCHANT_ADMIN.getKey())) {
            throw new BizException("商户管理管理员账号不能禁用");
        }
        if (accountType.equals(AccountTypeEnum.MERCHANT_MEMBER.getKey())) {
            log.info("商户成员账号禁用");
        }
        if (accountType.equals(AccountTypeEnum.PROJECT_MEMBER.getKey())) {
            log.info("项目成员账号禁用");
        }
        boolean accountEnable = authService.accountEnable(sysUserDO);
        if (!accountEnable) {
            throw new BizException("账号禁用启用失败");
        }
        redisService.del(String.format(RedisConstant.LOGIN_INFO_KEY, sysUserDO.getAccount()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void platformAccountResetPwd(PrimaryIdDTO dto) {
        SysUserDO sysUserDO = sysUserDOMapper.selectById(dto.getId());
        if (sysUserDO == null) {
            throw new BizException("账号不存在");
        }
        boolean updateAccountPwd = authService.updateAccountPwd(sysUserDO, AccountConstant.DEFAULT_PWD);
        if (!updateAccountPwd) {
            throw new BizException("重置密码失败");
        }
        redisService.del(String.format(RedisConstant.LOGIN_INFO_KEY, sysUserDO.getAccount()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void platformAccountDel(PrimaryIdDTO dto) {
        SysUserDO sysUserDO = sysUserDOMapper.selectById(dto.getId());
        if (sysUserDO == null) {
            throw new BizException("账号不存在");
        }
        Integer accountType = sysUserDO.getAccountType();
        if (accountType.equals(AccountTypeEnum.PLATFORM_ADMIN.getKey())) {
            if (sysUserDO.getIsAdmin().equals(IsAdminEnum.ADMIN.getKey())) {
                throw new BizException("初始化平台管理员账号不能删除");
            }
            sysUserRoleDOMapper.delete(new LambdaQueryWrapper<SysUserRoleDO>()
                    .eq(SysUserRoleDO::getUserId, sysUserDO.getId())
                    .eq(SysUserRoleDO::getBelong, BelongEnum.PLATFORM.getKey()));
        }
        if (accountType.equals(AccountTypeEnum.MERCHANT_ADMIN.getKey())) {
            throw new BizException("商户管理管理员账号不能删除");
        }
        if (accountType.equals(AccountTypeEnum.MERCHANT_MEMBER.getKey())) {
            sysUserRoleDOMapper.delete(new LambdaQueryWrapper<SysUserRoleDO>()
                    .eq(SysUserRoleDO::getUserId, sysUserDO.getId())
                    .eq(SysUserRoleDO::getBelong, BelongEnum.MERCHANT.getKey()));
        }
        if (accountType.equals(AccountTypeEnum.PROJECT_MEMBER.getKey())) {
            // 移除项目用户角色关系
            Set<Long> userIdSet = new HashSet<>(1);
            userIdSet.add(sysUserDO.getId());
            projectService.removeProjectUserRole(userIdSet);
        }
        sysUserDOMapper.deleteById(sysUserDO.getId());
        redisService.del(String.format(RedisConstant.LOGIN_INFO_KEY, sysUserDO.getAccount()));
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void platformAccountUpdatePwd(AccountUpdatePwdReqDTO dto) {
        SysUserDO sysUserDO = sysUserDOMapper.selectById(dto.getId());
        if (sysUserDO == null) {
            throw new BizException("账号不存在");
        }
        String oldPwd = dto.getOldPwd();
        if (!passwordEncoder.matches(oldPwd, sysUserDO.getPassword())) {
            throw new BizException("原密码输入有误");
        }
        if (!dto.getNewPwd().equals(dto.getConfirmPwd())) {
            throw new BizException("新密码前后输入不一致");
        }
        boolean updateAccountPwd = authService.updateAccountPwd(sysUserDO, dto.getConfirmPwd());
        if (!updateAccountPwd) {
            throw new BizException("修改密码失败");
        }
        redisService.del(String.format(RedisConstant.LOGIN_INFO_KEY, sysUserDO.getAccount()));
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void platformAccountUpdatePhone(AccountUpdatePhoneReqDTO dto) {
        SysUserDO sysUserDO = sysUserDOMapper.selectById(SecurityUtil.getUserId());
        if (sysUserDO == null) {
            throw new BizException("账号不存在");
        }
        String oldPhone = dto.getOldPhone();
        String newPhone = dto.getNewPhone();
        if (!oldPhone.equals(sysUserDO.getAccount())) {
            throw new BizException("原手机号输入有误");
        }
        if (!newPhone.equals(dto.getConfirmPhone())) {
            throw new BizException("新手机号前后输入不一致");
        }
        Integer belong = sysUserDO.getBelong();
        Integer accountType = sysUserDO.getAccountType();
        //平台管理员、商户管理员才能修改手机号，商户成员、项目成员不显示第二行的绑定手机号
        if (!belong.equals(BelongEnum.PLATFORM.getKey())) {
            throw new BizException("该账号为非平台级账号,不能修改手机号");
        }
        if (!accountType.equals(AccountTypeEnum.PLATFORM_ADMIN.getKey())) {
            throw new BizException("该账号非平台管理员账号，不能修改手机号");
        }
        if (sysUserDO.getIsAdmin().equals(IsAdminEnum.ADMIN.getKey())) {
            throw new BizException("初始化平台管理员账号，不能修改手机号");
        }
        Long count = new LambdaQueryChainWrapper<>(sysUserDOMapper)
                .eq(SysUserDO::getAccount, newPhone).count();
        if (count > 0) {
            throw new BizException("该手机号已被注册使用");
        }
        // 初始化平台管理员手机号不能修改，平台管理员修改手机号不能添加已有手机号号注册，商户管理员修改手机号不能添加已成为平台级的手机号
        boolean updateAccount = authService.updateAccount(sysUserDO, newPhone);
        if (!updateAccount) {
            throw new BizException("更新账号（手机号）失败");
        }
        redisService.del(String.format(RedisConstant.LOGIN_INFO_KEY, oldPhone));
        redisService.del(String.format(RedisConstant.LOGIN_INFO_KEY, newPhone));
    }


}
